package com.adcc.swingui.ui;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import javax.swing.ScrollPaneConstants;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup;
import javax.swing.plaf.metal.MetalComboBoxUI;

/**
 * @ClassName: JComboCheckBox
 * @Description: 多选下拉框 添加选项用addItem(new JComboCheckBox.ComboCheckBoxEntry())
 * @author: LIWEN
 * @date:2015-8-7 上午08:10:56
 */
public class JComboCheckBox extends JComboBox {

	private int maxWidth = 300;

	public JComboCheckBox() {
		super();
		setRenderer(new ComboCheckBoxRenderer());
		updateUI();
	}

	public JComboCheckBox(String[] items) {
		super();
		setRenderer(new ComboCheckBoxRenderer());
		addItems(items);
		updateUI();
	}

	public JComboCheckBox(Vector<String> items) {
		super();
		setRenderer(new ComboCheckBoxRenderer());
		addItems(items.toArray(new String[0]));
		updateUI();
	}

	public JComboCheckBox(int maxWidth) {
		super();
		this.maxWidth = maxWidth;
		setRenderer(new ComboCheckBoxRenderer());
		updateUI();
	}

	public JComboCheckBox(String[] items, int maxWidth) {
		super();
		this.maxWidth = maxWidth;
		setRenderer(new ComboCheckBoxRenderer());
		addItems(items);
		updateUI();
	}

	public JComboCheckBox(Vector<String> items, int maxWidth) {
		super();
		this.maxWidth = maxWidth;
		setRenderer(new ComboCheckBoxRenderer());
		addItems(items.toArray(new String[0]));
		updateUI();
	}

	public void addItems(String[] items) {
		for (int i = 0; i < items.length; i++) {
			String string = items[i];
			this.addItem(new ComboCheckBoxEntry(String.valueOf(i + 1), string));
		}
	}

	/**
	 * @Title: addItem
	 * @Description: 添加选项
	 * @param item
	 * @return void
	 * @throws
	 */
	public void addItem(ComboCheckBoxEntry item) {
		super.addItem(item);
	}

	/**
	 * @Title: addItem
	 * @Description: 添加选项
	 * @param checked
	 *            是否选中
	 * @param state
	 *            选中状态
	 * @param id
	 *            key
	 * @param value
	 * @return void
	 * @throws
	 */
	public void addItem(boolean checked, boolean state, String id, String value) {
		super.addItem(new ComboCheckBoxEntry(checked, state, id, value));
	}

	/**
	 * @Title: getText
	 * @Description: 得到文本框内容
	 * @param
	 * @return String
	 * @throws
	 */
	public String getText() {

		return ((JTextField) getEditor().getEditorComponent()).getText();

	}

	/**
	 * @Title: setText
	 * @Description: 设置文本框内容
	 * @param @param text
	 * @return void
	 * @throws
	 */
	public void setText(String text) {

		((JTextField) getEditor().getEditorComponent()).setText(text);

	}

	/**
	 * @Title: getCheckedCodes
	 * @Description: 得到所有选中项的id值，用String数组返回
	 * @param @return
	 * @return String[]
	 * @throws
	 */
	public String[] getCheckedCodes() {

		Vector values = new Vector();
		DefaultComboBoxModel model = (DefaultComboBoxModel) getModel();
		for (int i = 0; i < model.getSize(); i++) {
			ComboCheckBoxEntry item = (ComboCheckBoxEntry) model.getElementAt(i);
			boolean checked = item.getChecked();
			if (checked) {
				values.add(item.getUniqueCode());
			}
		}
		String[] retVal = new String[values.size()];
		values.copyInto(retVal);
		return retVal;

	}

	/**
	 * @Title: getCheckedValues
	 * @Description: 得到所有选中项的value值，用String数组返回
	 * @param @return
	 * @return String[]
	 * @throws
	 */
	public String[] getCheckedValues() {

		Vector values = new Vector();
		DefaultComboBoxModel model = (DefaultComboBoxModel) getModel();
		for (int i = 0; i < model.getSize(); i++) {
			ComboCheckBoxEntry item = (ComboCheckBoxEntry) model.getElementAt(i);
			boolean checked = item.getChecked();
			if (checked) {
				values.add(item.getValue());
			}
		}
		String[] retVal = new String[values.size()];
		values.copyInto(retVal);
		return retVal;

	}

	/**
	 * @Title: getCheckedUserObject
	 * @Description: TODO 得到所有选中项关联的对象
	 * @param @return
	 * @return List<Object>
	 * @throws
	 */
	public List<Object> getCheckedUserObject() {

		List<Object> selectItems = new ArrayList<Object>();
		DefaultComboBoxModel model = (DefaultComboBoxModel) getModel();
		for (int i = 0; i < model.getSize(); i++) {
			ComboCheckBoxEntry item = (ComboCheckBoxEntry) model.getElementAt(i);
			boolean checked = item.getChecked();
			if (checked) {
				selectItems.add(item.getUserObject());
			}
		}
		return selectItems;

	}

	/**
	 * @Title: isSelected
	 * @Description: TODO 比较输入的参数是否选中
	 * @param @param uniqueCode
	 * @param @return
	 * @return boolean
	 * @throws
	 */
	public boolean isSelected(String uniqueCode) {
		Vector values = new Vector();
		DefaultComboBoxModel model = (DefaultComboBoxModel) getModel();
		for (int i = 0; i < model.getSize(); i++) {
			ComboCheckBoxEntry item = (ComboCheckBoxEntry) model.getElementAt(i);
			boolean checked = item.getChecked();
			if (checked) {
				values.add(item.getUniqueCode());
			}
		}

		return values.contains(uniqueCode);
	}

	/**
	 * @Title: isSelected
	 * @Description: TODO 比较输入的参数是否选中
	 * @param @param uniqueCode
	 * @param @return
	 * @return boolean
	 * @throws
	 */
	public int getCheckedItems() {
		int selectItem = 0;
		DefaultComboBoxModel model = (DefaultComboBoxModel) getModel();
		for (int i = 0; i < model.getSize(); i++) {
			ComboCheckBoxEntry item = (ComboCheckBoxEntry) model.getElementAt(i);
			boolean checked = item.getChecked();
			if (checked) {
				selectItem++;
			}
		}

		return selectItem;
	}

	public String getCheckedCodesToString() {

		String result = null;
		Vector values = new Vector();
		DefaultComboBoxModel model = (DefaultComboBoxModel) getModel();

		for (int i = 0; i < model.getSize(); i++) {
			ComboCheckBoxEntry item = (ComboCheckBoxEntry) model.getElementAt(i);
			boolean checked = item.getChecked();
			if (checked) {
				values.add(item.getUniqueCode().trim());
			}
		}

		if (values.size() > 0) {
			result = values.toString();
			result = result.substring(1, result.length() - 1);
		}
		return result;
	}

	/**
	 * @Title: removeChecked
	 * @Description: 清空选中项
	 * @param
	 * @return void
	 * @throws
	 */
	public void removeChecked() {

		DefaultComboBoxModel model = (DefaultComboBoxModel) getModel();
		for (int i = 0; i < model.getSize(); i++) {
			ComboCheckBoxEntry item = (ComboCheckBoxEntry) model.getElementAt(i);
			item.setChecked(false);
		}
		setText("");

	}

	@Override
	public void updateUI() {
		setEditable(true);

		setUI(new ComboCheckBoxUI(maxWidth));
	}

	public static void main(String[] args) {

		JFrame frame = new JFrame();
		frame.setSize(650, 580);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		JPanel jPanel = new JPanel();

		String[] values = new String[] { "11111111111", "2222222", "33333333", "4444444444444", "55555555", "666666666", "777777", "66666", "777777", "66666", "777777777" };
		final JComboCheckBox checkBox = new JComboCheckBox(values);
		checkBox.setEditable(true);
		checkBox.setPreferredSize(new Dimension(150, 30));
		jPanel.add(checkBox);
		checkBox.addItem(new ComboCheckBoxEntry(false, false, "77", "dasa"));

		JButton btnCode = new JButton("Code");
		btnCode.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				for (String string : checkBox.getCheckedCodes()) {
					System.out.print(string + " ");
				}
				System.out.println("");

				System.out.println(checkBox.getCheckedCodesToString());
			}
		});
		jPanel.add(btnCode);

		JButton btnValue = new JButton("Value");
		btnValue.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				for (String string : checkBox.getCheckedValues()) {
					System.out.print(string + " ");
				}
				System.out.println("");
			}
		});
		jPanel.add(btnValue);

		frame.getContentPane().add(jPanel);
		frame.setVisible(true);

	}

	class ComboCheckBoxRenderer extends JCheckBox implements ListCellRenderer, Serializable {

		protected Border noFocusBorder;

		public ComboCheckBoxRenderer() {

			super();
			if (noFocusBorder == null) {
				noFocusBorder = new EmptyBorder(1, 1, 1, 1);
			}
			setOpaque(true);
			setBorder(noFocusBorder);

		}

		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {

			setComponentOrientation(list.getComponentOrientation());

			if (isSelected) {
				setBackground(list.getSelectionBackground());
				setForeground(list.getSelectionForeground());
			} else {
				setBackground(list.getBackground());
				setForeground(list.getForeground());
			}

			if (value instanceof ComboCheckBoxEntry) {
				ComboCheckBoxEntry item = (ComboCheckBoxEntry) value;
				setSelected(item.getChecked());
				setToolTipText(item.getValue());
				setText(item.getValue());
			} else {
				setText((value == null) ? "" : value.toString());
			}

			setEnabled(list.isEnabled());
			setFont(list.getFont());
			setBorder((cellHasFocus) ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder);

			return this;

		}
	}

	class ComboCheckBoxUI extends MetalComboBoxUI {

		public int maxWidth = 300;

		public ComboCheckBoxUI() {
		}

		public ComboCheckBoxUI(int maxWidth) {
			this.maxWidth = maxWidth;
		}

		@Override
		protected ComboPopup createPopup() {

			ComboCheckPopUp popUp = new ComboCheckPopUp(comboBox, maxWidth);
			popUp.getAccessibleContext().setAccessibleParent(comboBox);

			return popUp;

		}

		public class ComboCheckPopUp extends BasicComboPopup {

			private int width = -1;
			private int maxWidth = 300;

			public ComboCheckPopUp(JComboBox cBox, int maxWidth) {
				super(cBox);
				this.maxWidth = maxWidth;

			}

			@Override
			protected JScrollPane createScroller() {
				return new JScrollPane(list, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
			}

			@Override
			protected MouseListener createListMouseListener() {
				return new CheckBoxListMouseHandler();
			}

			@Override
			public void show() {

				Dimension popupSize = comboBox.getSize();
				Insets insets = getInsets();
				popupSize.setSize(popupSize.width - (insets.right + insets.left), getPopupHeightForRowCount(comboBox.getMaximumRowCount()));

				int maxWidthOfCell = calcPreferredWidth();
				width = maxWidthOfCell;

				if (comboBox.getItemCount() > comboBox.getMaximumRowCount()) {
					width += scroller.getVerticalScrollBar().getPreferredSize().width;
				}

				if (width > this.maxWidth) {
					width = this.maxWidth;
				}

				if (width < this.comboBox.getWidth()) {
					width = this.comboBox.getWidth();
				}

				if (maxWidthOfCell > width) {
					popupSize.height += scroller.getHorizontalScrollBar().getPreferredSize().height;
				}

				Rectangle popupBounds = computePopupBounds(0, comboBox.getBounds().height, width, popupSize.height);
				scroller.setMaximumSize(popupBounds.getSize());
				scroller.setPreferredSize(popupBounds.getSize());
				scroller.setMinimumSize(popupBounds.getSize());
				list.invalidate();
				syncListSelectionWithComboBoxSelection();
				list.ensureIndexIsVisible(list.getSelectedIndex());
				setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled());
				show(comboBox, popupBounds.x, popupBounds.y);

			}

			private int calcPreferredWidth() {
				int prefferedWidth = 0;
				ListCellRenderer renderer = list.getCellRenderer();
				for (int index = 0, count = list.getModel().getSize(); index < count; index++) {
					Object element = list.getModel().getElementAt(index);
					Component comp = renderer.getListCellRendererComponent(list, element, index, false, false);
					Dimension dim = comp.getPreferredSize();
					if (dim.width > prefferedWidth) {
						prefferedWidth = dim.width;
					}
				}

				return prefferedWidth;
			}

			void syncListSelectionWithComboBoxSelection() {
				int selectedIndex = comboBox.getSelectedIndex();
				if (selectedIndex == -1) {
					list.clearSelection();
				} else {
					list.setSelectedIndex(selectedIndex);
				}
			}

			public void setPopupWidth(int width) {
				this.width = width;
			}

			protected class CheckBoxListMouseHandler extends MouseAdapter {

				@Override
				public void mousePressed(MouseEvent anEvent) {
					int index = list.getSelectedIndex();
					ComboCheckBoxEntry item = (ComboCheckBoxEntry) list.getModel().getElementAt(index);
					boolean checked = !item.getChecked();
					int size = list.getModel().getSize();

					item.setChecked(checked);

					Vector<Object> v = new Vector<Object>();
					for (int i = 0; i < size; i++) {
						ComboCheckBoxEntry ccbe = (ComboCheckBoxEntry) list.getModel().getElementAt(i);
						if (ccbe.getChecked()) {
							v.add(ccbe.getValue());
						}
					}

					JTextField tx = (JTextField) (comboBox.getEditor().getEditorComponent());
					tx.setText(v.size() > 0 ? v.toString() : "");
					tx.setBorder(null);
					updateListBoxSelectionForEvent(anEvent, false);
					Rectangle rect = list.getCellBounds(0, size - 1);
					list.repaint(rect);
				}

			}
		}
	}

	/**
	 * @ClassName: ComboCheckBoxEntry
	 * @Description: 多选下拉列表框数据封装类
	 * @author: Liwen
	 * @date:2015-8-7 上午08:28:45
	 */
	public static class ComboCheckBoxEntry {

		/** 是否选中 */
		boolean checked;
		/** 选项编辑状态 */
		boolean state;
		/** 选项id */
		String uniqueCode;
		/** 选项值 */
		String value;
		/** 关联对象 */
		Object userObject;

		public ComboCheckBoxEntry() {
			this.checked = false;
			this.state = true;
			this.uniqueCode = "-1";
			this.value = "Empty Entry";
		}

		public ComboCheckBoxEntry(String uniqueCode, String value) {
			this.checked = false;
			this.state = true;
			this.uniqueCode = uniqueCode;
			this.value = value;
		}

		public ComboCheckBoxEntry(boolean checked, String uniqueCode, String value) {
			this.checked = checked;
			this.state = true;
			this.uniqueCode = uniqueCode;
			this.value = value;
		}

		public ComboCheckBoxEntry(boolean checked, boolean state, String uniqueCode, String value) {
			this.checked = checked;
			this.state = state;
			this.uniqueCode = uniqueCode;
			this.value = value;
		}

		public boolean getChecked() {
			return checked;
		}

		public void setChecked(boolean checked) {
			this.checked = checked;
		}

		public String getUniqueCode() {
			return uniqueCode;
		}

		public String getValue() {
			return value;
		}

		public boolean getState() {
			return state;
		}

		public Object getUserObject() {
			return userObject;
		}

		public void setUserObject(Object userObject) {
			this.userObject = userObject;
		}

		@Override
		public String toString() {
			// TODO Auto-generated method stub
			return "";
		}

	}

}